package com.young.sso.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.io.Serializable;

/**
 * 配置redis操作数据(key/value)的时候运用的序列化格式(string、jdk、jackson2)
 *
 * @author young
 * @date 2021/11/25 10:48
 */
@Configuration
public class RedisSerializable implements Serializable {
    // 为了在service中调用redis的操作类, 提前通过@Bean的方式准备好

    /**
     * redisTemplate<K,V>操作redis的主体对象，序列化的配置在redisTemplate中体现
     * K:Key的泛型参数，用String来表示
     * V:Value的泛型类型。为了把5中类型(String/Class/List/Set)都概括，所以用Object
     *
     * @param factory redisConnectionFactory:spring从当前配置中加载pool连接池配置和redis基础连接配置项生成的
     * @return RedisTemplate
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        // 实例化一个RedisTemplate对象(操作redis中不同数据类型的CRUD)
        RedisTemplate<String, Object> redistemplate = new RedisTemplate<>();
        // 给template配置一个factory，指定连接
        redistemplate.setConnectionFactory(factory);

        // 配置序列化器:
        // 针对String和hash采用何种序列化方式(java把数据传给redis时使用何种格式: jdk/string/jackson)
        // 指定两种序列化器
        // Jackson序列化器
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        // jackson转换json格式的核心类
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL,
                JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // 在java包中创建Controller控制器
        // PS：注意，这里放置的位置是包的根目录，目的是为了控制器的包扫描
        // MainController类中的代码如下(@SpringBootApplication拥有扫描功能，扫描此目录下的所有类，所
        // 以官方建议放置在根目录下)
        // String序列化器 name(主要用在key上)
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

        // key采用String的序列化方式
        redistemplate.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化方式
        redistemplate.setHashKeySerializer(stringRedisSerializer);

        // value序列化方式采用jackson
        // user[name=张三] -> {"user":{"name":"张三"}}
        redistemplate.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        redistemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redistemplate.afterPropertiesSet();
        return redistemplate;
    }
}
